package com.vshining.cryptoki.jna;

import com.sun.jna.Function;
import com.sun.jna.NativeLibrary;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.ptr.NativeLongByReference;
import com.sun.jna.ptr.PointerByReference;
import com.vshining.cryptoki.CryptokiException;
import com.vshining.cryptoki.jna.pkcs11.CK_FUNCTION_LIST;
import com.vshining.cryptoki.jna.pkcs11t.CK_ATTRIBUTE;
import com.vshining.cryptoki.jna.pkcs11t.CK_C_INITIALIZE_ARGS;
import com.vshining.cryptoki.jna.pkcs11t.CK_INFO;
import com.vshining.cryptoki.jna.pkcs11t.CK_MECHANISM;
import com.vshining.cryptoki.jna.pkcs11t.CK_MECHANISM_INFO;
import com.vshining.cryptoki.jna.pkcs11t.CK_NOTIFY;
import com.vshining.cryptoki.jna.pkcs11t.CK_RV;
import com.vshining.cryptoki.jna.pkcs11t.CK_SESSION_INFO;
import com.vshining.cryptoki.jna.pkcs11t.CK_SLOT_INFO;
import com.vshining.cryptoki.jna.pkcs11t.CK_TOKEN_INFO;
import com.vshining.cryptoki.jna.pkcs11t.CK_VERSION;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Shining Wang <shiningwang@vshining.com>
 */
@SuppressWarnings("unused")
public class CryptokiWrapper {
    private Logger log = LoggerFactory.getLogger(CryptokiWrapper.class);
    private NativeLibrary library;
    private CK_FUNCTION_LIST functionList;

    private static final Map<String, CryptokiWrapper> cache = new HashMap<String, CryptokiWrapper>();

    protected CryptokiWrapper(String libraryName, String functionName, int alignType) throws CryptokiException {
        log.info("PKCS#11 library name is " + libraryName);
        log.info("C_GET_FUNCTION_LIST function name is " + functionName);
        log.info("align type is " + alignType);
        NativeLibrary library = NativeLibrary.getInstance(libraryName);
        Function function = library.getFunction(functionName);
        PointerByReference pFunctionList = new PointerByReference();
        NativeLong rv = (NativeLong) function.invoke(NativeLong.class, new Object[]{pFunctionList});
        CK_RV.ckAssertReturnValueOK(rv);
        this.functionList = new CK_FUNCTION_LIST(pFunctionList.getValue(), alignType);
        this.functionList.read();
    }

    public static CryptokiWrapper getInstance(String libraryName) throws CryptokiException {
        CryptokiWrapper p11 = cache.get(libraryName);
        if (p11 == null) {
            p11 = new CryptokiWrapper(libraryName, "C_GetFunctionList", Structure.ALIGN_DEFAULT);
            cache.put(libraryName, p11);
        }
        return p11;
    }

	/*- ****************************************************************************
     * CK_VERSION version
	 ******************************************************************************/

    /**
     * return CK_FUNCTION_LIST version
     */
    public CK_VERSION getVersion() {
        return functionList.version;
    }

	/*- ****************************************************************************
     * #include "pkcs11f.h"
	 ******************************************************************************/

	/* General-purpose */

    /**
     * [General-purpose] <br>
     * C_Initialize initializes the Cryptoki library.
     *
     * @param pInitArgs [CK_VOID_PTR] <br>
     *                  if this is not NULL_PTR, it gets cast to
     *                  CK_C_INITIALIZE_ARGS_PTR and dereferenced
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_Initialize(CK_C_INITIALIZE_ARGS pInitArgs) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_Initialize");
        log.trace("CK_C_INITIALIZE_ARGS: " + pInitArgs);
        rv = functionList.C_Initialize.invoke(pInitArgs);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [General-purpose] <br>
     * C_Finalize indicates that an application is done with the Cryptoki
     * library.
     *
     * @param pReserved [CK_VOID_PTR] <br>
     *                  reserved. Should be NULL_PTR
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_Finalize(Pointer pReserved) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_Finalize");
        log.trace("pReserved: " + pReserved);
        rv = functionList.C_Finalize.invoke(pReserved);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [General-purpose] <br>
     * C_GetInfo returns general information about Cryptoki.
     *
     * @param pInfo [CK_INFO_PTR] <br>
     *              location that receives information
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_GetInfo(CK_INFO pInfo) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_GetInfo");
        log.trace("CK_INFO: " + (pInfo != null ? pInfo.getPointer() : null));
        rv = functionList.C_GetInfo.invoke(pInfo);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("CK_INFO: " + pInfo);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [General-purpose] <br>
     * C_GetFunctionList returns the function list.
     *
     * @param ppFunctionList [CK_FUNCTION_LIST_PTR_PTR] <br>
     *                       receives pointer to function list
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_GetFunctionList(PointerByReference ppFunctionList) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_GetFunctionList");
        rv = functionList.C_GetFunctionList.invoke(ppFunctionList);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("ppFunctionList: " + ppFunctionList);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

	/* Slot and token management */

    /**
     * [Slot and token management] <br>
     * C_GetSlotList obtains a list of slots in the system.
     *
     * @param tokenPresent [CK_BBOOL] <br>
     *                     only slots with tokens?
     * @param pSlotList    [CK_SLOT_ID_PTR] <br>
     *                     receives array of slot IDs
     * @param pulCount     [CK_ULONG_PTR] <br>
     *                     receives number of slots
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_GetSlotList(byte tokenPresent, NativeLong[] pSlotList, NativeLongByReference pulCount) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_GetSlotList");
        log.trace("tokenPresent: " + tokenPresent);
        log.trace("pSlotList: " + (pSlotList != null ? "(" + pSlotList.length * NativeLong.SIZE + " bytes, size " + pSlotList.length + ")" : null));
        log.trace("pulCount: " + pulCount);
        rv = functionList.C_GetSlotList.invoke(tokenPresent, pSlotList, pulCount);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("pSlotList: " + ToString.toString(pSlotList));
        log.trace("pulCount: " + ToString.toString(pulCount));
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Slot and token management] <br>
     * C_GetSlotInfo obtains information about a particular slot in the system.
     *
     * @param slotID [CK_SLOT_ID] <br>
     *               ID of the token's slot
     * @param pInfo  [CK_SLOT_INFO_PTR] <br>
     *               receives the slot information
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_GetSlotInfo(NativeLong slotID, CK_SLOT_INFO pInfo) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_GetSlotInfo");
        log.trace("slotID: " + slotID);
        log.trace("CK_SLOT_INFO: " + ToString.toString(pInfo));
        rv = functionList.C_GetSlotInfo.invoke(slotID, pInfo);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("CK_SLOT_INFO: " + pInfo);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Slot and token management] <br>
     * C_GetTokenInfo obtains information about a particular token in the
     * system.
     *
     * @param slotID [CK_SLOT_ID] <br>
     *               ID of the token's slot
     * @param pInfo  [CK_TOKEN_INFO_PTR] <br>
     *               receives the token information
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_GetTokenInfo(NativeLong slotID, CK_TOKEN_INFO pInfo) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_GetTokenInfo");
        log.trace("slotID: " + slotID);
        log.trace("CK_TOKEN_INFO: " + ToString.toString(pInfo));
        rv = functionList.C_GetTokenInfo.invoke(slotID, pInfo);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("CK_TOKEN_INFO: " + pInfo);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Slot and token management] <br>
     * C_GetMechanismList obtains a list of mechanism types supported by a
     * token.
     *
     * @param slotID         [CK_SLOT_ID] <br>
     *                       ID of the token's slot
     * @param pMechanismList [CK_MECHANISM_TYPE_PTR] <br>
     *                       gets mech. array
     * @param pulCount       [CK_ULONG_PTR] <br>
     *                       gets # of mechs.
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_GetMechanismList(NativeLong slotID, NativeLong[] pMechanismList, NativeLongByReference pulCount) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_GetMechanismList");
        log.trace("slotID: " + slotID);
        if (pMechanismList != null) {
            for (int i = 0; i < pMechanismList.length; i++) {
                log.trace("pMechanismList[" + i + "]: " + pMechanismList[i]);
            }
        } else {
            log.trace("pMechanismList: null");
        }
        log.trace("pulCount: " + pulCount);
        rv = functionList.C_GetMechanismList.invoke(slotID, pMechanismList, pulCount);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        if (pMechanismList != null) {
            for (int i = 0; i < pMechanismList.length; i++) {
                log.trace("pMechanismList[" + i + "]: " + pMechanismList[i]);
            }
        } else {
            log.trace("pMechanismList: null");
        }
        log.trace("pulCount: " + ToString.toString(pulCount));
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Slot and token management] <br>
     * C_GetMechanismInfo obtains information about a particular mechanism
     * possibly supported by a token.
     *
     * @param slotID [CK_SLOT_ID] <br>
     *               ID of the token's slot
     * @param type   [CK_MECHANISM_TYPE] <br>
     *               type of mechanism
     * @param pInfo  [CK_MECHANISM_INFO_PTR] <br>
     *               receives mechanism info
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_GetMechanismInfo(NativeLong slotID, NativeLong type, CK_MECHANISM_INFO pInfo) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_GetMechanismInfo");
        log.trace("slotID: " + slotID);
        log.trace("type: " + ToString.toHexString(type.intValue()));
        log.trace("CK_MECHANISM_INFO: " + pInfo);
        rv = functionList.C_GetMechanismInfo.invoke(slotID, type, pInfo);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("CK_MECHANISM_INFO: " + pInfo);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Slot and token management] <br>
     * C_InitToken initializes a token.
     *
     * @param slotID   [CK_SLOT_ID] <br>
     *                 ID of the token's slot
     * @param pPin     [CK_UTF8CHAR_PTR] <br>
     *                 the SO's initial PIN
     * @param ulPinLen [CK_ULONG] <br>
     *                 length in bytes of the PIN
     * @param pLabel   [CK_UTF8CHAR_PTR] <br>
     *                 32-byte token label (blank padded)<br>
     *                 <em>pLabel changed from CK_CHAR_PTR to CK_UTF8CHAR_PTR for v2.10</em>
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_InitToken(NativeLong slotID, Pointer pPin, NativeLong ulPinLen, Pointer pLabel) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_InitToken");
        rv = functionList.C_InitToken.invoke(slotID, pPin, ulPinLen, pLabel);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Slot and token management] <br>
     * C_InitPIN initializes the normal user's PIN.
     *
     * @param hSession [CK_SESSION_HANDLE] <br>
     *                 the session's handle
     * @param pPin     [CK_UTF8CHAR_PTR] <br>
     *                 the SO's initial PIN
     * @param ulPinLen [CK_ULONG] <br>
     *                 length in bytes of the PIN
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_InitPIN(NativeLong hSession, Pointer pPin, NativeLong ulPinLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_InitPIN");
        rv = functionList.C_InitPIN.invoke(hSession, pPin, ulPinLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Slot and token management] <br>
     * C_SetPIN modifies the PIN of the user who is logged in.
     *
     * @param hSession    [CK_SESSION_HANDLE] <br>
     *                    the session's handle
     * @param pOldPin     [CK_UTF8CHAR_PTR] <br>
     *                    the old PIN
     * @param ulOldPinLen [CK_ULONG] <br>
     *                    length of the old PIN
     * @param pNewPin     [CK_UTF8CHAR_PTR] <br>
     *                    the new PIN
     * @param ulNewPinLen [CK_ULONG] <br>
     *                    length of the new PIN
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_SetPIN(NativeLong hSession, Pointer pOldPin, NativeLong ulOldPinLen, Pointer pNewPin, NativeLong ulNewPinLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_SetPIN");
        rv = functionList.C_SetPIN.invoke(hSession, pOldPin, ulOldPinLen, pNewPin, ulNewPinLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

	/* Session management */

    /**
     * [Session management] <br>
     * C_OpenSession opens a session between an application and a token.
     *
     * @param slotID       [CK_SLOT_ID] <br>
     *                     the slot's ID
     * @param flags        [CK_FLAGS] <br>
     *                     from CK_SESSION_INFO
     * @param pApplication [CK_VOID_PTR] <br>
     *                     passed to callback
     * @param Notify       [CK_NOTIFY] <br>
     *                     callback function
     * @param phSession    [CK_SESSION_HANDLE_PTR] <br>
     *                     gets session handle
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_OpenSession(NativeLong slotID, NativeLong flags, Pointer pApplication, CK_NOTIFY Notify, NativeLongByReference phSession) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_GetMechanismInfo");
        log.trace("slotID: " + slotID);
        log.trace("flags: " + ToString.toHexString(flags.longValue()));
        log.trace("pApplication: " + pApplication);
        log.trace("Notify: " + Notify);
        log.trace("phSession: " + phSession);
        rv = functionList.C_OpenSession.invoke(slotID, flags, pApplication, Notify, phSession);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("phSession: " + phSession);
        log.trace("hSession: " + phSession.getValue());
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Session management] <br>
     * C_CloseSession closes a session between an application and a token.
     *
     * @param hSession [CK_SESSION_HANDLE] <br>
     *                 the session's handle
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_CloseSession(NativeLong hSession) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_CloseSession");
        log.trace("hSession: " + hSession);
        rv = functionList.C_CloseSession.invoke(hSession);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Session management] <br>
     * C_CloseAllSessions closes all sessions with a token.
     *
     * @param slotID [CK_SLOT_ID] <br>
     *               the slot's ID
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_CloseAllSessions(NativeLong slotID) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_CloseAllSessions");
        rv = functionList.C_CloseAllSessions.invoke(slotID);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Session management] <br>
     * C_GetSessionInfo obtains information about the session.
     *
     * @param hSession [CK_SESSION_HANDLE] <br>
     *                 the session's handle
     * @param pInfo    [CK_SESSION_INFO_PTR] <br>
     *                 receives session info
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_GetSessionInfo(NativeLong hSession, CK_SESSION_INFO pInfo) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_GetSessionInfo");
        rv = functionList.C_GetSessionInfo.invoke(hSession, pInfo);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Session management] <br>
     * C_GetOperationState obtains the state of the cryptographic operation in a
     * session.
     *
     * @param hSession             [CK_SESSION_HANDLE] <br>
     *                             the session's handle
     * @param pOperationState      [CK_BYTE_PTR] <br>
     *                             gets state
     * @param pulOperationStateLen [CK_ULONG_PTR] <br>
     *                             gets state
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_GetOperationState(NativeLong hSession, Pointer pOperationState, NativeLongByReference pulOperationStateLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_GetOperationState");
        rv = functionList.C_GetOperationState.invoke(hSession, pOperationState, pulOperationStateLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Session management] <br>
     * C_SetOperationState restores the state of the cryptographic operation in
     * a session.
     *
     * @param hSession             [CK_SESSION_HANDLE] <br>
     *                             the session's handle
     * @param pOperationState      [CK_BYTE_PTR] <br>
     *                             holds state
     * @param pulOperationStateLen [CK_ULONG] <br>
     *                             holds state length
     * @param hEncryptionKey       [CK_OBJECT_HANDLE] <br>
     *                             en/decryption key
     * @param hAuthenticationKey   [CK_OBJECT_HANDLE] <br>
     *                             sign/verify key
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_SetOperationState(NativeLong hSession, Pointer pOperationState, NativeLong pulOperationStateLen, NativeLong hEncryptionKey, NativeLong hAuthenticationKey) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_SetOperationState");
        rv = functionList.C_SetOperationState.invoke(hSession, pOperationState, pulOperationStateLen, hEncryptionKey, hAuthenticationKey);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Session management] <br>
     * C_Login logs a user into a token.
     *
     * @param hSession [CK_SESSION_HANDLE] <br>
     *                 the session's handle
     * @param userType [CK_USER_TYPE] <br>
     *                 the user type
     * @param pPin     [CK_UTF8CHAR_PTR] <br>
     *                 the user's PIN
     * @param ulPinLen [CK_ULONG] <br>
     *                 the length of the PIN
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_Login(NativeLong hSession, NativeLong userType, Pointer pPin, NativeLong ulPinLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_Login");
        log.trace("hSession: " + hSession);
        log.trace("userType: " + ToString.toHexString(userType.intValue()));
        log.trace("pPin: " + pPin);
        log.trace("pin: " + pPin.getString(0));
        log.trace("ulPinLen: " + ulPinLen);
        rv = functionList.C_Login.invoke(hSession, userType, pPin, ulPinLen);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Session management] <br>
     * C_Logout logs a user out from a token.
     *
     * @param hSession [CK_SESSION_HANDLE] <br>
     *                 the session's handle
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_Logout(NativeLong hSession) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_Logout");
        log.trace("hSession: " + hSession);
        rv = functionList.C_Logout.invoke(hSession);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

	/* Object management */

    /**
     * [Object management] <br>
     * C_CreateObject creates a new object.
     *
     * @param hSession  [CK_SESSION_HANDLE] <br>
     *                  the session's handle
     * @param pTemplate [CK_ATTRIBUTE_PTR] <br>
     *                  the object's template
     * @param ulCount   [CK_ULONG] <br>
     *                  attributes in template
     * @param phObject  [CK_OBJECT_HANDLE_PTR] <br>
     *                  gets new object's handle.
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_CreateObject(NativeLong hSession, CK_ATTRIBUTE[] pTemplate, NativeLong ulCount, NativeLongByReference phObject) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_CreateObject");
        rv = functionList.C_CreateObject.invoke(hSession, pTemplate, ulCount, phObject);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Object management] <br>
     * C_CopyObject copies an object, creating a new object for the copy.
     *
     * @param hSession    [CK_SESSION_HANDLE] <br>
     *                    the session's handle
     * @param hObject     [CK_OBJECT_HANDLE] <br>
     *                    the object's handle
     * @param pTemplate   [CK_ATTRIBUTE_PTR] <br>
     *                    template for new object
     * @param ulCount     [CK_ULONG] <br>
     *                    attributes in template
     * @param phNewObject [CK_OBJECT_HANDLE_PTR] <br>
     *                    attributes in template
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_CopyObject(NativeLong hSession, NativeLong hObject, CK_ATTRIBUTE[] pTemplate, NativeLong ulCount, NativeLongByReference phNewObject) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_CopyObject");
        rv = functionList.C_CopyObject.invoke(hSession, hObject, pTemplate, ulCount, phNewObject);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Object management] <br>
     * C_DestroyObject destroys an object.
     *
     * @param hSession [CK_SESSION_HANDLE] <br>
     *                 the session's handle
     * @param hObject  [CK_OBJECT_HANDLE] <br>
     *                 the object's handle
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_DestroyObject(NativeLong hSession, NativeLong hObject) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_DestroyObject");
        rv = functionList.C_DestroyObject.invoke(hSession, hObject);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Object management] <br>
     * C_GetObjectSize gets the size of an object in bytes.
     *
     * @param hSession [CK_SESSION_HANDLE] <br>
     *                 the session's handle
     * @param hObject  [CK_OBJECT_HANDLE] <br>
     *                 the object's handle
     * @param pulSize  [CK_ULONG_PTR] <br>
     *                 receives size of object
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_GetObjectSize(NativeLong hSession, NativeLong hObject, NativeLongByReference pulSize) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_GetObjectSize");
        rv = functionList.C_GetObjectSize.invoke(hSession, hObject, pulSize);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Object management] <br>
     * C_GetAttributeValue obtains the value of one or more object attributes.
     *
     * @param hSession  [CK_SESSION_HANDLE] <br>
     *                  the session's handle
     * @param hObject   [CK_OBJECT_HANDLE] <br>
     *                  the object's handle
     * @param pTemplate [CK_ATTRIBUTE_PTR] <br>
     *                  specifies attrs; gets vals
     * @param ulCount   [CK_ULONG] <br>
     *                  attributes in template
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_GetAttributeValue(NativeLong hSession, NativeLong hObject, CK_ATTRIBUTE[] pTemplate, NativeLong ulCount) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_GetAttributeValue");
        log.trace("hSession: " + hSession);
        log.trace("hObject: " + ToString.toHexString(hObject.intValue()));
        if (pTemplate != null) {
            for (int i = 0; i < pTemplate.length; i++) {
                log.trace("pTemplate[" + i + "]: " + (pTemplate[i].pValue != null ? pTemplate[i] : null));
            }
        } else {
            log.trace("pTemplate: null");
        }
        log.trace("ulCount: " + ulCount);
        rv = functionList.C_GetAttributeValue.invoke(hSession, hObject, pTemplate, ulCount);
        if (pTemplate != null) {
            for (int i = 0; i < pTemplate.length; i++) {
                log.trace("pTemplate[" + i + "]: " + (pTemplate[i].pValue != null ? pTemplate[i] : null));
            }
        } else {
            log.trace("pTemplate: null");
        }
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Object management] <br>
     * C_SetAttributeValue modifies the value of one or more object attributes
     *
     * @param hSession  [CK_SESSION_HANDLE] <br>
     *                  the session's handle
     * @param hObject   [CK_OBJECT_HANDLE] <br>
     *                  the object's handle
     * @param pTemplate [CK_ATTRIBUTE_PTR] <br>
     *                  specifies attrs and values
     * @param ulCount   [CK_ULONG] <br>
     *                  attributes in template
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_SetAttributeValue(NativeLong hSession, NativeLong hObject, CK_ATTRIBUTE[] pTemplate, NativeLong ulCount) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_SetAttributeValue");
        rv = functionList.C_SetAttributeValue.invoke(hSession, hObject, pTemplate, ulCount);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Object management] <br>
     * C_FindObjectsInit initializes a search for token and session objects that
     * match a template.
     *
     * @param hSession  [CK_SESSION_HANDLE] <br>
     *                  the session's handle
     * @param pTemplate [CK_ATTRIBUTE_PTR] <br>
     *                  attribute values to match
     * @param ulCount   [CK_ULONG] <br>
     *                  attrs in search template
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_FindObjectsInit(NativeLong hSession, CK_ATTRIBUTE[] pTemplate, NativeLong ulCount) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_FindObjectsInit");
        log.trace("hSession: " + hSession);
        if (pTemplate != null) {
            for (int i = 0; i < pTemplate.length; i++) {
                log.trace("pTemplate[" + i + "]: " + pTemplate[i]);
            }
        } else {
            log.trace("pTemplate: null");
        }
        log.trace("ulCount: " + ulCount);
        rv = functionList.C_FindObjectsInit.invoke(hSession, pTemplate, ulCount);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Object management] <br>
     * C_FindObjects continues a search for token and session objects that match
     * a template, obtaining additional object handles.
     *
     * @param hSession         [CK_SESSION_HANDLE] <br>
     *                         session's handle
     * @param phObject         [CK_OBJECT_HANDLE_PTR] <br>
     *                         gets obj. handles
     * @param ulMaxObjectCount [CK_ULONG] <br>
     *                         max handles to get
     * @param pulObjectCount   [CK_ULONG_PTR] <br>
     *                         actual # returned
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_FindObjects(NativeLong hSession, NativeLong[] phObject, NativeLong ulMaxObjectCount, NativeLongByReference pulObjectCount) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_FindObjects");
        log.trace("hSession: " + hSession);
        log.trace("phObject: " + ToString.toHexString(phObject));
        log.trace("ulMaxObjectCount: " + ulMaxObjectCount);
        log.trace("pulObjectCount: " + pulObjectCount);
        rv = functionList.C_FindObjects.invoke(hSession, phObject, ulMaxObjectCount, pulObjectCount);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        for (int i = 0; phObject != null && i < phObject.length; i++) {
            log.trace("pTemplate[" + i + "]: "
                    + ToString.toHexString(phObject[i].intValue()));
        }
        log.trace("ulObjectCount: "
                + (pulObjectCount != null ? pulObjectCount.getValue() : null));
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Object management] <br>
     * C_FindObjectsFinal finishes a search for token and session objects.
     *
     * @param hSession [CK_SESSION_HANDLE] <br>
     *                 session's handle
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_FindObjectsFinal(NativeLong hSession) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_FindObjectsFinal");
        log.trace("hSession: " + hSession);
        rv = functionList.C_FindObjectsFinal.invoke(hSession);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

	/* Encryption and decryption */

    /**
     * [Encryption and decryption] <br>
     * C_EncryptInit initializes an encryption operation.
     *
     * @param hSession   [CK_SESSION_HANDLE] <br>
     *                   session's handle
     * @param pMechanism [CK_MECHANISM_PTR] <br>
     *                   the encryption mechanism
     * @param hKey       [CK_OBJECT_HANDLE] <br>
     *                   handle of encryption key
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_EncryptInit(NativeLong hSession, CK_MECHANISM pMechanism, NativeLong hKey) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_EncryptInit");
        rv = functionList.C_EncryptInit.invoke(hSession, pMechanism, hKey);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Encryption and decryption] <br>
     * C_Encrypt encrypts single-part data.
     *
     * @param hSession            [CK_SESSION_HANDLE] <br>
     *                            session's handle
     * @param pData               [CK_BYTE_PTR] <br>
     *                            the plaintext data
     * @param ulDataLen           [CK_ULONG] <br>
     *                            bytes of plaintext
     * @param pEncryptedData      [CK_BYTE_PTR] <br>
     *                            gets ciphertext
     * @param pulEncryptedDataLen [CK_ULONG_PTR] <br>
     *                            gets c-text size
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_Encrypt(NativeLong hSession, Pointer pData, NativeLong ulDataLen, Pointer pEncryptedData, NativeLongByReference pulEncryptedDataLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_Encrypt");
        rv = functionList.C_Encrypt.invoke(hSession, pData, ulDataLen, pEncryptedData, pulEncryptedDataLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Encryption and decryption] <br>
     * C_EncryptUpdate continues a multiple-part encryption operation.
     *
     * @param hSession            [CK_SESSION_HANDLE] <br>
     *                            session's handle
     * @param pPart               [CK_BYTE_PTR] <br>
     *                            the plaintext data
     * @param ulPartLen           [CK_ULONG] <br>
     *                            plaintext data len
     * @param pEncryptedPart      [CK_BYTE_PTR] <br>
     *                            gets ciphertext
     * @param pulEncryptedPartLen [CK_ULONG_PTR] <br>
     *                            gets c-text size
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_EncryptUpdate(NativeLong hSession, Pointer pPart, NativeLong ulPartLen, Pointer pEncryptedPart, NativeLongByReference pulEncryptedPartLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_EncryptUpdate");
        rv = functionList.C_EncryptUpdate.invoke(hSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Encryption and decryption] <br>
     * C_EncryptFinal finishes a multiple-part encryption operation.
     *
     * @param hSession                [CK_SESSION_HANDLE] <br>
     *                                session handle
     * @param pLastEncryptedPart      [CK_BYTE_PTR] <br>
     *                                last c-text
     * @param pulLastEncryptedPartLen [CK_ULONG_PTR] <br>
     *                                gets last size
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_EncryptFinal(NativeLong hSession, Pointer pLastEncryptedPart, NativeLongByReference pulLastEncryptedPartLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_EncryptFinal");
        rv = functionList.C_EncryptFinal.invoke(hSession, pLastEncryptedPart, pulLastEncryptedPartLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Encryption and decryption] <br>
     * C_DecryptInit initializes a decryption operation.
     *
     * @param hSession   [CK_SESSION_HANDLE] <br>
     *                   the session's handle
     * @param pMechanism [CK_MECHANISM_PTR] <br>
     *                   the decryption mechanism
     * @param hKey       [CK_OBJECT_HANDLE] <br>
     *                   handle of decryption key
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_DecryptInit(NativeLong hSession, CK_MECHANISM pMechanism, NativeLong hKey) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_DecryptInit");
        rv = functionList.C_DecryptInit.invoke(hSession, pMechanism, hKey);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Encryption and decryption] <br>
     * C_Decrypt decrypts encrypted data in a single part.
     *
     * @param hSession           [CK_SESSION_HANDLE] <br>
     *                           session's handle
     * @param pEncryptedData     [CK_BYTE_PTR] <br>
     *                           ciphertext
     * @param ulEncryptedDataLen [CK_ULONG] <br>
     *                           ciphertext length
     * @param pData              [CK_BYTE_PTR] <br>
     *                           gets plaintext
     * @param pulDataLen         [CK_ULONG_PTR] <br>
     *                           gets p-text size
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_Decrypt(NativeLong hSession, Pointer pEncryptedData, NativeLong ulEncryptedDataLen, Pointer pData, NativeLongByReference pulDataLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_Decrypt");
        rv = functionList.C_Decrypt.invoke(hSession, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Encryption and decryption] <br>
     * C_DecryptUpdate continues a multiple-part decryption operation.
     *
     * @param hSession           [CK_SESSION_HANDLE] <br>
     *                           session's handle
     * @param pEncryptedPart     [CK_BYTE_PTR] <br>
     *                           encrypted data
     * @param ulEncryptedPartLen [CK_ULONG] <br>
     *                           input length
     * @param pPart              [CK_BYTE_PTR] <br>
     *                           gets plaintext
     * @param pulPartLen         [CK_ULONG_PTR] <br>
     *                           p-text size
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_DecryptUpdate(NativeLong hSession, Pointer pEncryptedPart, NativeLong ulEncryptedPartLen, Pointer pPart, NativeLongByReference pulPartLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_DecryptUpdate");
        rv = functionList.C_DecryptUpdate.invoke(hSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Encryption and decryption] <br>
     * C_DecryptFinal finishes a multiple-part decryption operation.
     *
     * @param hSession       [CK_SESSION_HANDLE] <br>
     *                       the session's handle
     * @param pLastPart      [CK_BYTE_PTR] <br>
     *                       gets plaintext
     * @param pulLastPartLen [CK_ULONG_PTR] <br>
     *                       p-text size
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_DecryptFinal(NativeLong hSession, Pointer pLastPart, NativeLongByReference pulLastPartLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_DecryptFinal");
        rv = functionList.C_DecryptFinal.invoke(hSession, pLastPart, pulLastPartLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

	/* Message digesting */

    /**
     * [Message digesting] <br>
     * C_DigestInit initializes a message-digesting operation.
     *
     * @param hSession   [CK_SESSION_HANDLE] <br>
     *                   the session's handle
     * @param pMechanism [CK_MECHANISM_PTR] <br>
     *                   the digesting mechanism
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_DigestInit(NativeLong hSession, CK_MECHANISM pMechanism) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_DigestInit");
        rv = functionList.C_DigestInit.invoke(hSession, pMechanism);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Message digesting] <br>
     * C_Digest digests data in a single part.
     *
     * @param hSession     [CK_SESSION_HANDLE] <br>
     *                     the session's handle
     * @param pData        [CK_BYTE_PTR] <br>
     *                     data to be digested
     * @param ulDataLen    [CK_ULONG] <br>
     *                     bytes of data to digest
     * @param pDigest      [CK_BYTE_PTR] <br>
     *                     gets the message digest
     * @param pulDigestLen [CK_ULONG_PTR] <br>
     *                     gets digest length
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_Digest(NativeLong hSession, Pointer pData, NativeLong ulDataLen, Pointer pDigest, NativeLongByReference pulDigestLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_Digest");
        rv = functionList.C_Digest.invoke(hSession, pData, ulDataLen, pDigest, pulDigestLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Message digesting] <br>
     * C_DigestUpdate continues a multiple-part message-digesting operation.
     *
     * @param hSession  [CK_SESSION_HANDLE] <br>
     *                  the session's handle
     * @param pPart     [CK_BYTE_PTR] <br>
     *                  data to be digested
     * @param ulPartLen [CK_ULONG] <br>
     *                  bytes of data to be digested
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_DigestUpdate(NativeLong hSession, Pointer pPart, NativeLong ulPartLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_DigestUpdate");
        rv = functionList.C_DigestUpdate.invoke(hSession, pPart, ulPartLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Message digesting] <br>
     * C_DigestKey continues a multi-part message-digesting operation, by
     * digesting the value of a secret key as part of the data already digested.
     *
     * @param hSession [CK_SESSION_HANDLE] <br>
     *                 the session's handle
     * @param hKey     [CK_OBJECT_HANDLE] <br>
     *                 secret key to digest
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_DigestKey(NativeLong hSession, NativeLong hKey) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_DigestKey");
        rv = functionList.C_DigestKey.invoke(hSession, hKey);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Message digesting] <br>
     * C_DigestFinal finishes a multiple-part message-digesting operation.
     *
     * @param hSession     [CK_SESSION_HANDLE] <br>
     *                     the session's handle
     * @param pDigest      [CK_BYTE_PTR] <br>
     *                     gets the message digest
     * @param pulDigestLen [CK_ULONG_PTR] <br>
     *                     gets byte count of digest
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_DigestFinal(NativeLong hSession, Pointer pDigest, NativeLongByReference pulDigestLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_DigestFinal");
        rv = functionList.C_DigestFinal.invoke(hSession, pDigest, pulDigestLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

	/* Signing and MACing */

    /**
     * [Signing and MACing] <br>
     * C_SignInit initializes a signature (private key encryption) operation,     * where the signature is (will be) an appendix to the data, and plaintext
     * cannot be recovered from the signature.
     *
     * @param hSession   [CK_SESSION_HANDLE] <br>
     *                   the session's handle
     * @param pMechanism [CK_MECHANISM_PTR] <br>
     *                   the signature mechanism
     * @param hKey       [CK_OBJECT_HANDLE] <br>
     *                   handle of signature key
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_SignInit(NativeLong hSession, CK_MECHANISM pMechanism, NativeLong hKey) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_SignInit");
        log.trace("hSession: " + hSession);
        log.trace("pMechanism: " + pMechanism);
        log.trace("hKey: " + ToString.toHexString(hKey.intValue()));
        rv = functionList.C_SignInit.invoke(hSession, pMechanism, hKey);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Signing and MACing] <br>
     * <p/>
     * C_Sign signs (encrypts with private key) data in a single part, where the
     * signature is (will be) an appendix to the data, and plaintext cannot be
     * recovered from the signature
     *
     * @param hSession        [CK_SESSION_HANDLE] <br>
     *                        the session's handle
     * @param pData           [CK_BYTE_PTR] <br>
     *                        the data to sign
     * @param ulDataLen       [CK_ULONG] <br>
     *                        count of bytes to sign
     * @param pSignature      [CK_BYTE_PTR] <br>
     *                        gets the signature
     * @param pulSignatureLen [CK_ULONG_PTR] <br>
     *                        gets signature length
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_Sign(NativeLong hSession, Pointer pData, NativeLong ulDataLen, Pointer pSignature, NativeLongByReference pulSignatureLen) {
        NativeLong rv;
        String _msg = null;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_Sign");
        log.trace("hSession: " + hSession);
        log.trace("pData: " + pData);
        if (pData != null) {
            _msg = ToString.toHexString(pData.getByteArray(0, ulDataLen.intValue()));
        }
        log.trace("data: " + _msg);
        log.trace("pSignature: " + pSignature);
        log.trace("pulSignatureLen: " + pulSignatureLen);
        rv = functionList.C_Sign.invoke(hSession, pData, ulDataLen, pSignature, pulSignatureLen);
        if (pSignature != null) {
            _msg = ToString.toHexString(pSignature.getByteArray(0, pulSignatureLen.getValue().intValue()));
        }
        log.trace("signature: " + _msg);
        log.trace("ulSignatureLen: " + pulSignatureLen.getValue());
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Signing and MACing] <br>
     * C_SignUpdate continues a multiple-part signature operation, where the
     * signature is (will be) an appendix to the data, and plaintext cannot be
     * recovered from the signature.
     *
     * @param hSession  [CK_SESSION_HANDLE] <br>
     *                  the session's handle
     * @param pPart     [CK_BYTE_PTR] <br>
     *                  the data to sign
     * @param ulPartLen [CK_ULONG] <br>
     *                  count of bytes to sign
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_SignUpdate(NativeLong hSession, Pointer pPart, NativeLong ulPartLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_SignUpdate");
        rv = functionList.C_SignUpdate.invoke(hSession, pPart, ulPartLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Signing and MACing] <br>
     * C_SignFinal finishes a multiple-part signature operation, returning the
     * signature.
     *
     * @param hSession        [CK_SESSION_HANDLE] <br>
     *                        the session's handle
     * @param pSignature      [CK_BYTE_PTR] <br>
     *                        gets the signature
     * @param pulSignatureLen [CK_ULONG_PTR] <br>
     *                        gets signature length
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_SignFinal(NativeLong hSession, Pointer pSignature, NativeLongByReference pulSignatureLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_SignFinal");
        rv = functionList.C_SignFinal.invoke(hSession, pSignature, pulSignatureLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Signing and MACing] <br>
     * C_SignRecoverInit initializes a signature operation, where the data can
     * be recovered from the signature.
     *
     * @param hSession   [CK_SESSION_HANDLE] <br>
     *                   the session's handle
     * @param pMechanism [CK_MECHANISM_PTR] <br>
     *                   the signature mechanism
     * @param hKey       [CK_OBJECT_HANDLE] <br>
     *                   handle of the signature key
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_SignRecoverInit(NativeLong hSession, CK_MECHANISM pMechanism, NativeLong hKey) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_SignRecoverInit");
        rv = functionList.C_SignRecoverInit.invoke(hSession, pMechanism, hKey);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Signing and MACing] <br>
     * C_SignRecover signs data in a single operation, where the data can be
     * recovered from the signature.
     *
     * @param hSession        [CK_SESSION_HANDLE] <br>
     *                        the session's handle
     * @param pData           [CK_BYTE_PTR] <br>
     *                        the data to sign
     * @param ulDataLen       [CK_ULONG] <br>
     *                        count of bytes to sign
     * @param pSignature      [CK_BYTE_PTR] <br>
     *                        gets the signature
     * @param pulSignatureLen [CK_ULONG_PTR] <br>
     *                        gets signature length
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_SignRecover(NativeLong hSession, Pointer pData, NativeLong ulDataLen, Pointer pSignature, NativeLongByReference pulSignatureLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_SignRecover");
        rv = functionList.C_SignRecover.invoke(hSession, pData, ulDataLen, pSignature, pulSignatureLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

	/* Verifying signatures and MACs */

    /**
     * [Verifying signatures and MACs] <br>
     * C_VerifyInit initializes a verification operation, where the signature is
     * an appendix to the data, and plaintext cannot cannot be recovered from
     * the signature (e.g. DSA).
     *
     * @param hSession   [CK_SESSION_HANDLE] <br>
     *                   the session's handle
     * @param pMechanism [CK_MECHANISM_PTR] <br>
     *                   the verification mechanism
     * @param hKey       [CK_OBJECT_HANDLE] <br>
     *                   verification key
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_VerifyInit(NativeLong hSession, CK_MECHANISM pMechanism, NativeLong hKey) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_VerifyInit");
        rv = functionList.C_VerifyInit.invoke(hSession, pMechanism, hKey);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Verifying signatures and MACs] <br>
     * C_Verify verifies a signature in a single-part operation, where the
     * signature is an appendix to the data, and plaintext cannot be recovered
     * from the signature.
     *
     * @param hSession       [CK_SESSION_HANDLE] <br>
     *                       the session's handle
     * @param pData          [CK_BYTE_PTR] <br>
     *                       signed data
     * @param ulDataLen      [CK_ULONG] <br>
     *                       length of signed data
     * @param pSignature     [CK_BYTE_PTR] <br>
     *                       signature
     * @param ulSignatureLen [CK_ULONG] <br>
     *                       signature length
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_Verify(NativeLong hSession, Pointer pData, NativeLong ulDataLen, Pointer pSignature, NativeLong ulSignatureLen) {
        NativeLong rv;
        String _msg = null;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_Verify");
        log.trace("hSession: " + hSession);
        log.trace("pData: " + pData);
        log.trace("ulDataLen: " + ulDataLen);
        if (pData != null) {
            _msg = ""
                    + ToString.toHexString(pData.getByteArray(0, ulDataLen.intValue()));
        }
        log.trace("data: " + _msg);
        log.trace("pSignature: " + pSignature);
        log.trace("ulSignatureLen: " + ulSignatureLen);
        if (pSignature != null) {
            _msg = ToString.toHexString(pSignature.getByteArray(0, ulSignatureLen.intValue()));
        }
        log.trace("signature: " + _msg);
        rv = functionList.C_Verify.invoke(hSession, pData, ulDataLen, pSignature, ulSignatureLen);
        log.trace("CK_RV: " + ToString.toHexString(rv.intValue()));
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Verifying signatures and MACs] <br>
     * C_VerifyUpdate continues a multiple-part verification operation, where
     * the signature is an appendix to the data, and plaintext cannot be
     * recovered from the signature.
     *
     * @param hSession  [CK_SESSION_HANDLE] <br>
     *                  the session's handle
     * @param pPart     [CK_BYTE_PTR] <br>
     *                  signed data
     * @param ulPartLen [CK_ULONG] <br>
     *                  length of signed data
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_VerifyUpdate(NativeLong hSession, Pointer pPart, NativeLong ulPartLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_VerifyUpdate");
        rv = functionList.C_VerifyUpdate.invoke(hSession, pPart, ulPartLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Verifying signatures and MACs] <br>
     * C_VerifyFinal finishes a multiple-part verification operation, checking
     * the signature.
     *
     * @param hSession       [CK_SESSION_HANDLE] <br>
     *                       the session's handle
     * @param pSignature     [CK_BYTE_PTR] <br>
     *                       signature to verify
     * @param ulSignatureLen [CK_ULONG] <br>
     *                       signature length
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_VerifyFinal(NativeLong hSession, Pointer pSignature, NativeLong ulSignatureLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_VerifyFinal");
        rv = functionList.C_VerifyFinal.invoke(hSession, pSignature, ulSignatureLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Verifying signatures and MACs] <br>
     * C_VerifyRecoverInit initializes a signature verification operation, where
     * the data is recovered from the signature.
     *
     * @param hSession   [CK_SESSION_HANDLE] <br>
     *                   the session's handle
     * @param pMechanism [CK_MECHANISM_PTR] <br>
     *                   the verification mechanism
     * @param hKey       [CK_OBJECT_HANDLE] <br>
     *                   verification key
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_VerifyRecoverInit(NativeLong hSession, CK_MECHANISM pMechanism, NativeLong hKey) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_VerifyRecoverInit");
        rv = functionList.C_VerifyRecoverInit.invoke(hSession, pMechanism, hKey);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Verifying signatures and MACs] <br>
     * C_VerifyRecover verifies a signature in a single-part operation, where
     * the data is recovered from the signature.
     *
     * @param hSession       [CK_SESSION_HANDLE] <br>
     *                       the session's handle
     * @param pSignature     [CK_BYTE_PTR] <br>
     *                       signature to verify
     * @param ulSignatureLen [CK_ULONG] <br>
     *                       signature length
     * @param pData          [CK_BYTE_PTR] <br>
     *                       gets signed data
     * @param pulDataLen     [CK_ULONG_PTR] <br>
     *                       gets signed data len
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_VerifyRecover(NativeLong hSession, Pointer pSignature, NativeLong ulSignatureLen, Pointer pData, NativeLongByReference pulDataLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_VerifyRecover");
        rv = functionList.C_VerifyRecover.invoke(hSession, pSignature, ulSignatureLen, pData, pulDataLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

	/* Dual-function cryptographic operations */

    /**
     * [Dual-function cryptographic operations] <br>
     * C_DigestEncryptUpdate continues a multiple-part digesting and encryption
     * operation.
     *
     * @param hSession            [CK_SESSION_HANDLE] <br>
     *                            session's handle
     * @param pPart               [CK_BYTE_PTR] <br>
     *                            the plaintext data
     * @param ulPartLen           [CK_ULONG] <br>
     *                            plaintext length
     * @param pEncryptedPart      [CK_BYTE_PTR] <br>
     *                            gets ciphertext
     * @param pulEncryptedPartLen [CK_ULONG_PTR] <br>
     *                            gets c-text length
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_DigestEncryptUpdate(NativeLong hSession, Pointer pPart, NativeLong ulPartLen, Pointer pEncryptedPart, NativeLongByReference pulEncryptedPartLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_DigestEncryptUpdate");
        rv = functionList.C_DigestEncryptUpdate.invoke(hSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Dual-function cryptographic operations] <br>
     * C_DecryptDigestUpdate continues a multiple-part decryption and digesting
     * operation.
     *
     * @param hSession           [CK_SESSION_HANDLE] <br>
     *                           session's handle
     * @param pEncryptedPart     [CK_BYTE_PTR] <br>
     *                           ciphertext
     * @param ulEncryptedPartLen [CK_ULONG] <br>
     *                           ciphertext length
     * @param pPart              [CK_BYTE_PTR] <br>
     *                           gets plaintext
     * @param pulPartLen         [CK_ULONG_PTR] <br>
     *                           gets plaintext len
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_DecryptDigestUpdate(NativeLong hSession, Pointer pEncryptedPart, NativeLong ulEncryptedPartLen, Pointer pPart, NativeLongByReference pulPartLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_DecryptDigestUpdate");
        rv = functionList.C_DecryptDigestUpdate.invoke(hSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Dual-function cryptographic operations] <br>
     * C_SignEncryptUpdate continues a multiple-part signing and encryption
     * operation.
     *
     * @param hSession            [CK_SESSION_HANDLE] <br>
     *                            session's handle
     * @param pPart               [CK_BYTE_PTR] <br>
     *                            the plaintext data
     * @param ulPartLen           [CK_ULONG] <br>
     *                            plaintext length
     * @param pEncryptedPart      [CK_BYTE_PTR] <br>
     *                            gets ciphertext
     * @param pulEncryptedPartLen [CK_ULONG_PTR] <br>
     *                            gets c-text length
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_SignEncryptUpdate(NativeLong hSession, Pointer pPart, NativeLong ulPartLen, Pointer pEncryptedPart, NativeLongByReference pulEncryptedPartLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_SignEncryptUpdate");
        rv = functionList.C_SignEncryptUpdate.invoke(hSession, pPart, ulPartLen, pEncryptedPart, pulEncryptedPartLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Dual-function cryptographic operations] <br>
     * C_DecryptVerifyUpdate continues a multiple-part decryption and verify
     * operation.
     *
     * @param hSession           [CK_SESSION_HANDLE] <br>
     *                           session's handle
     * @param pEncryptedPart     [CK_BYTE_PTR] <br>
     *                           ciphertext
     * @param ulEncryptedPartLen [CK_ULONG] <br>
     *                           ciphertext length
     * @param pPart              [CK_BYTE_PTR] <br>
     *                           gets plaintext
     * @param pulPartLen         [CK_ULONG_PTR] <br>
     *                           gets p-text length
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_DecryptVerifyUpdate(NativeLong hSession, Pointer pEncryptedPart, NativeLong ulEncryptedPartLen, Pointer pPart, NativeLongByReference pulPartLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_DecryptVerifyUpdate");
        rv = functionList.C_DecryptVerifyUpdate.invoke(hSession, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

	/* Key management */

    /**
     * [Key management] <br>
     * C_GenerateKey generates a secret key, creating a new key object.
     *
     * @param hSession   [CK_SESSION_HANDLE] <br>
     *                   the session's handle
     * @param pMechanism [CK_MECHANISM_PTR] <br>
     *                   key generation mech.
     * @param pTemplate  [CK_ATTRIBUTE_PTR] <br>
     *                   template for new key
     * @param ulCount    [CK_ULONG] <br>
     *                   # of attrs in template
     * @param phKey      [CK_OBJECT_HANDLE_PTR] <br>
     *                   gets handle of new key
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_GenerateKey(NativeLong hSession, CK_MECHANISM pMechanism, CK_ATTRIBUTE[] pTemplate, NativeLong ulCount, NativeLongByReference phKey) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_GenerateKey");
        rv = functionList.C_GenerateKey.invoke(hSession, pMechanism, pTemplate, ulCount, phKey);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Key management] <br>
     * C_GenerateKeyPair generates a public-key/private-key pair, creating new
     * key objects.
     *
     * @param hSession                   [CK_SESSION_HANDLE] <br>
     *                                   session handle
     * @param pMechanism                 [CK_MECHANISM_PTR] <br>
     *                                   key-gen mech.
     * @param pPublicKeyTemplate         [CK_ATTRIBUTE_PTR] <br>
     *                                   template for pub. key
     * @param ulPublicKeyAttributeCount  [CK_ULONG] <br>
     *                                   # pub. attrs.
     * @param pPrivateKeyTemplate        [CK_ATTRIBUTE_PTR] <br>
     *                                   template for priv. key
     * @param ulPrivateKeyAttributeCount [CK_ULONG] <br>
     *                                   # priv. attrs.
     * @param phPublicKey                [CK_OBJECT_HANDLE_PTR] <br>
     *                                   gets pub. key handle
     * @param phPrivateKey               [CK_OBJECT_HANDLE_PTR] <br>
     *                                   gets priv. key handle
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_GenerateKeyPair(NativeLong hSession, CK_MECHANISM pMechanism, CK_ATTRIBUTE[] pPublicKeyTemplate, NativeLong ulPublicKeyAttributeCount, CK_ATTRIBUTE[] pPrivateKeyTemplate, NativeLong ulPrivateKeyAttributeCount, NativeLongByReference phPublicKey, NativeLongByReference phPrivateKey) {
        log.trace("============CK_FUNCTION start==============");
        return functionList.C_GenerateKeyPair.invoke(hSession, pMechanism, pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey);
    }

    /**
     * [Key management] <br>
     * C_WrapKey wraps (i.e., encrypts) a key.
     *
     * @param hSession         [CK_SESSION_HANDLE] <br>
     *                         the session's handle
     * @param pMechanism       [CK_MECHANISM_PTR] <br>
     *                         the wrapping mechanism
     * @param hWrappingKey     [CK_OBJECT_HANDLE] <br>
     *                         wrapping key
     * @param hKey             [CK_OBJECT_HANDLE] <br>
     *                         key to be wrapped
     * @param pWrappedKey      [CK_BYTE_PTR] <br>
     *                         gets wrapped key
     * @param pulWrappedKeyLen [CK_ULONG_PTR] <br>
     *                         gets wrapped key size
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_WrapKey(NativeLong hSession, CK_MECHANISM pMechanism, NativeLong hWrappingKey, NativeLong hKey, Pointer pWrappedKey, NativeLongByReference pulWrappedKeyLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_WrapKey");
        rv = functionList.C_WrapKey.invoke(hSession, pMechanism, hWrappingKey, hKey, pWrappedKey, pulWrappedKeyLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Key management] <br>
     * C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new key object.
     *
     * @param hSession         [CK_SESSION_HANDLE] <br>
     *                         session's handle
     * @param pMechanism       [CK_MECHANISM_PTR] <br>
     *                         unwrapping mech.
     * @param hUnwrappingKey   [CK_OBJECT_HANDLE] <br>
     *                         unwrapping key
     * @param pWrappedKey      [CK_BYTE_PTR] <br>
     *                         the wrapped key
     * @param ulWrappedKeyLen  [CK_ULONG] <br>
     *                         wrapped key len
     * @param pTemplate        [CK_ATTRIBUTE_PTR] <br>
     *                         new key template
     * @param ulAttributeCount [CK_ULONG] <br>
     *                         template length
     * @param phKey            [CK_OBJECT_HANDLE_PTR] <br>
     *                         gets new handle
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_UnwrapKey(NativeLong hSession, CK_MECHANISM pMechanism, NativeLong hUnwrappingKey, Pointer pWrappedKey, NativeLong ulWrappedKeyLen, CK_ATTRIBUTE pTemplate, NativeLong ulAttributeCount, NativeLongByReference phKey) {
        log.trace("============CK_FUNCTION start==============");
        return functionList.C_UnwrapKey.invoke(hSession, pMechanism, hUnwrappingKey, pWrappedKey, ulWrappedKeyLen, pTemplate, ulAttributeCount, phKey);
    }

    /**
     * [Key management] <br>
     * C_DeriveKey derives a key from a base key, creating a new key object.
     *
     * @param hSession         [CK_SESSION_HANDLE] <br>
     *                         session's handle
     * @param pMechanism       [CK_MECHANISM_PTR] <br>
     *                         key deriv. mech.
     * @param hBaseKey         [CK_OBJECT_HANDLE] <br>
     *                         base key
     * @param pTemplate        [CK_ATTRIBUTE_PTR] <br>
     *                         new key template
     * @param ulAttributeCount [CK_ULONG] <br>
     *                         template length
     * @param phKey            [CK_OBJECT_HANDLE_PTR] <br>
     *                         gets new handle
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_DeriveKey(NativeLong hSession, CK_MECHANISM pMechanism, NativeLong hBaseKey, CK_ATTRIBUTE pTemplate, NativeLong ulAttributeCount, NativeLongByReference phKey) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_DeriveKey");
        rv = functionList.C_DeriveKey.invoke(hSession, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

	/* Random number generation */

    /**
     * [Random number generation] <br>
     * C_SeedRandom mixes additional seed material into the token's random
     * number generator.
     *
     * @param hSession  [CK_SESSION_HANDLE] <br>
     *                  the session's handle
     * @param pSeed     [CK_BYTE_PTR] <br>
     *                  the seed material
     * @param ulSeedLen [CK_ULONG] <br>
     *                  length of seed material
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_SeedRandom(NativeLong hSession, Pointer pSeed, NativeLong ulSeedLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_SeedRandom");
        rv = functionList.C_SeedRandom.invoke(hSession, pSeed, ulSeedLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Random number generation] <br>
     * C_GenerateRandom generates random data.
     *
     * @param hSession    [CK_SESSION_HANDLE] <br>
     *                    the session's handle
     * @param RandomData  [CK_BYTE_PTR] <br>
     *                    receives the random data
     * @param ulRandomLen [CK_ULONG] <br>
     *                    # of bytes to generate
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_GenerateRandom(NativeLong hSession, Pointer RandomData, NativeLong ulRandomLen) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_GenerateRandom");
        rv = functionList.C_GenerateRandom.invoke(hSession, RandomData, ulRandomLen);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

	/* Parallel function management */

    /**
     * [Parallel function management] <br>
     * C_GetFunctionStatus is a legacy function; it obtains an updated status of
     * a function running in parallel with an application.
     *
     * @param hSession [CK_SESSION_HANDLE] <br>
     *                 the session's handle
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_GetFunctionStatus(NativeLong hSession) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_GetFunctionStatus");
        rv = functionList.C_GetFunctionStatus.invoke(hSession);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Parallel function management] <br>
     * C_CancelFunction is a legacy function; it cancels a function running in
     * parallel.
     *
     * @param hSession [CK_SESSION_HANDLE] <br>
     *                 the session's handle
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_CancelFunction(NativeLong hSession) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_CancelFunction");
        rv = functionList.C_CancelFunction.invoke(hSession);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    /**
     * [Parallel function management] <br>
     * C_WaitForSlotEvent waits for a slot event (token insertion, removal,     * etc.) to occur.
     * <em>Functions added in for Cryptoki Version 2.01 or later</em>
     *
     * @param flags    [CK_FLAGS] <br>
     *                 blocking/nonblocking flag
     * @param pSlot    [CK_SLOT_ID_PTR] <br>
     *                 location that receives the slot ID
     * @param pRserved [CK_VOID_PTR] <br>
     *                 reserved. Should be NULL_PTR
     * @return {@link com.vshining.cryptoki.jna.pkcs11t.CK_RV}
     */
    public NativeLong C_WaitForSlotEvent(NativeLong flags, NativeLongByReference pSlot, Pointer pRserved) {
        NativeLong rv;
        log.trace("============CK_FUNCTION start==============");
        log.trace("CK_FUNCTION->C_WaitForSlotEvent");
        rv = functionList.C_WaitForSlotEvent.invoke(flags, pSlot, pRserved);
        log.trace("============CK_FUNCTION finish==============");
        return rv;
    }

    public static final int ALIGN_DEFAULT = Structure.ALIGN_DEFAULT;
    public static final int ALIGN_GNUC = Structure.ALIGN_GNUC;
    public static final int ALIGN_MSVC = Structure.ALIGN_MSVC;
    public static final int ALIGN_NONE = Structure.ALIGN_NONE;
}
